package com.atguigu.dga230315.governance.service.impl;

import com.atguigu.dga230315.dolphinscheduler.bean.TDsTaskDefinition;
import com.atguigu.dga230315.dolphinscheduler.bean.TDsTaskInstance;
import com.atguigu.dga230315.dolphinscheduler.service.TDsTaskDefinitionService;
import com.atguigu.dga230315.dolphinscheduler.service.TDsTaskInstanceService;
import com.atguigu.dga230315.governance.assess.Assessor;
import com.atguigu.dga230315.governance.assess.spec.TecOwnerAssess;
import com.atguigu.dga230315.governance.bean.AssessParam;
import com.atguigu.dga230315.governance.bean.GovernanceAssessDetail;
import com.atguigu.dga230315.governance.bean.GovernanceMetric;
import com.atguigu.dga230315.governance.mapper.GovernanceAssessDetailMapper;
import com.atguigu.dga230315.governance.service.*;
import com.atguigu.dga230315.governance.utils.SpringBeanProvider;
import com.atguigu.dga230315.meta.bean.TableMetaInfo;
import com.atguigu.dga230315.meta.bean.TableMetaInfoExtra;
import com.atguigu.dga230315.meta.service.TableMetaInfoExtraService;
import com.atguigu.dga230315.meta.service.TableMetaInfoService;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * <p>
 * 治理考评结果明细 服务实现类
 * </p>
 *
 * @author zhangjunyi
 * @since 2023-07-18
 */
@Service
@DS("dga")
public class GovernanceAssessDetailServiceImpl extends ServiceImpl<GovernanceAssessDetailMapper, GovernanceAssessDetail> implements GovernanceAssessDetailService {
    //声明连接池
    //参数说明：1.有几个线程 2.最大的容量 3.检查活跃的周期看链接是否还有人用 4.时间单位 5.队列
     ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(100,100,60, TimeUnit.SECONDS,new LinkedBlockingDeque<>());

    @Autowired
    TableMetaInfoService tableMetaInfoService;

    @Autowired
    TableMetaInfoExtraService tableMetaInfoExtraService;

    @Autowired
    GovernanceMetricService governanceMetricService;

    @Autowired
    TDsTaskInstanceService tDsTaskInstanceService;

    @Autowired
    TDsTaskDefinitionService tDsTaskDefinitionService;
    @Autowired
    GovernanceAssessTableService governanceAssessTableService;
    @Autowired
    GovernanceAssessTecOwnerService governanceAssessTecOwnerService;
    @Autowired
    GovernanceAssessGlobalService governanceAssessGlobalService;

    @Override
    public void governanceAssess(String assessDate) {
        //0.重复考评的时候删除已经考评的结果
        remove(new QueryWrapper<GovernanceAssessDetail>().eq("assess_date", assessDate));


        //1.获取所有表的元数据（TableMetaInfo&TableMetaInfoExtra）
 /*       //这种方式功能上是ok的 但是需要频繁查询数据库 查询tableMetaInfoList.size次
        List<TableMetaInfo> tableMetaInfoList = tableMetaInfoService.list(new QueryWrapper<TableMetaInfo>().inSql("assess_date", "select max(assess_date) from table_meta_info"));
        for (TableMetaInfo tableMetaInfo : tableMetaInfoList) {
            //根据表名和库名获取到对应的辅助信息
            TableMetaInfoExtra tableMetaInfoExtra = tableMetaInfoExtraService.getOne(new QueryWrapper<TableMetaInfoExtra>().eq("table_name", tableMetaInfo.getTableName()).eq("schema_name", tableMetaInfo.getSchemaName()));
            tableMetaInfo.setTableMetaInfoExtra(tableMetaInfoExtra);
        }*/

        //另一种方案 为了减少数据库的链接可以使用join关联两张表的数据
        List<TableMetaInfo> allTableMetaInfoList = tableMetaInfoService.getAllTableMetaInfoList();

        //将所有表的元数据封装为Map类型  k：表名（库名.表名）  v：TableMetaInfo
        HashMap<String, TableMetaInfo> fullNameToTableMetaInfoMap = new HashMap<>();
        for (TableMetaInfo tableMetaInfo : allTableMetaInfoList) {
            fullNameToTableMetaInfoMap.put(tableMetaInfo.getSchemaName() + "." + tableMetaInfo.getTableName(), tableMetaInfo);
        }


        //2.获取所有已启用的指标
        List<GovernanceMetric> governanceMetrics = governanceMetricService.list(new QueryWrapper<GovernanceMetric>().eq("is_disabled", "0"));

        //创建List集合用来存放考评后的明细数据GovernanceAssessDetail
        ArrayList<GovernanceAssessDetail> governanceAssessDetails = new ArrayList<>(allTableMetaInfoList.size() * governanceMetrics.size());

        //获取考评日期运行的任务信息
        List<TDsTaskInstance> tDsTaskInstanceByDt = tDsTaskInstanceService.getTDsTaskInstanceByDt(assessDate);

        //获取所有要考评表的任务定义信息 并且是考评日期运行过的表任务
        //获取到所有要考评表的 全表名
        List<String> allAssessFullTableName = allTableMetaInfoList.stream().map(tableMetaInfo -> tableMetaInfo.getSchemaName() + "." + tableMetaInfo.getTableName()).collect(Collectors.toList());

        Map<String, TDsTaskDefinition> tableDefinitionMapByDt = tDsTaskDefinitionService.getTableDefinitionMapByDt(assessDate, allAssessFullTableName);

        //创建集合用来收集异步编排中每次考评的结果
        ArrayList<CompletableFuture<GovernanceAssessDetail>> completableFutureArrayList = new ArrayList<>();


        //3.针对每张表对每个指标做考评(获取每张表和每个启用的指标)
        for (TableMetaInfo tableMetaInfo : allTableMetaInfoList) {
            for (GovernanceMetric governanceMetric : governanceMetrics) {
                //封装参数对象
                AssessParam assessParam = new AssessParam();
                assessParam.setTableMetaInfo(tableMetaInfo);
                assessParam.setGovernanceMetric(governanceMetric);
                assessParam.setAssessDate(assessDate);
                assessParam.setFullNameToTableMetaInfoMap(fullNameToTableMetaInfoMap);
                assessParam.setTDsTaskInstanceList(tDsTaskInstanceByDt);
                assessParam.setTDsTaskDefinition(tableDefinitionMapByDt.get(tableMetaInfo.getSchemaName()+"."+tableMetaInfo.getTableName()));

               /*这种方式每增加一个指标都需要再增加一个if判断然后创建对应的子对象  这样违背了代码的开闭原则 所以不建议
               if (governanceMetric.getMetricCode().equals("TEC_OWNER")){

                   Assessor assessor = new TecOwnerAssess();
                } else if () {

                }*/

                //如何解决 根据不同的考评指标 自动去获取不同的指标对象
//                Assessor assessor = new TecOwnerAssess();
                //通过容器结合名字去获取对应的对象
                Assessor assessor = SpringBeanProvider.getBean(governanceMetric.getMetricCode(), Assessor.class);
                CompletableFuture<GovernanceAssessDetail> governanceAssessDetailCompletableFuture = CompletableFuture.supplyAsync(new Supplier<GovernanceAssessDetail>() {
                    @Override
                    public GovernanceAssessDetail get() {
                        GovernanceAssessDetail governanceAssessDetail = assessor.mainAssess(assessParam);
                        return governanceAssessDetail;
                    }
                }, threadPoolExecutor);

                completableFutureArrayList.add(governanceAssessDetailCompletableFuture);
//                GovernanceAssessDetail governanceAssessDetail = assessor.mainAssess(assessParam);
//                governanceAssessDetails.add(governanceAssessDetail);

               /*
               //这种方式每增加一个指标都要再增加一段这个指标的考评逻辑  这样违背了代码的开闭原则 所以不建议
               //判断是否是有技术owner指标  通过metric_code进行判断
                if (governanceMetric.getMetricCode().equals("TEC_OWNER")){
                    GovernanceAssessDetail governanceAssessDetail = new GovernanceAssessDetail();
                    governanceAssessDetail.setAssessDate(assessDate);
                    governanceAssessDetail.setTableName(tableMetaInfo.getTableName());
                    governanceAssessDetail.setSchemaName(tableMetaInfo.getSchemaName());
                    governanceAssessDetail.setMetricId(governanceMetric.getId()+"");
                    governanceAssessDetail.setMetricName(governanceMetric.getMetricName());
                    governanceAssessDetail.setGovernanceType(governanceMetric.getGovernanceType());
                    governanceAssessDetail.setTecOwner(tableMetaInfo.getTableMetaInfoExtra().getTecOwnerUserName());
                    governanceAssessDetail.setAssessScore(BigDecimal.TEN);
                    try {
                        //考评是否有技术owner
                        if (tableMetaInfo.getTableMetaInfoExtra().getTecOwnerUserName()==null){
                            governanceAssessDetail.setAssessScore(BigDecimal.ZERO);
                            governanceAssessDetail.setAssessProblem("没有技术负责人");
                            String url = governanceMetric.getGovernanceUrl() + tableMetaInfo.getId();
                            governanceAssessDetail.setGovernanceUrl(url);
                        }
                    }catch (Exception e){
                        governanceAssessDetail.setIsAssessException("1");
                        StringWriter stringWriter = new StringWriter();
                        PrintWriter printWriter = new PrintWriter(stringWriter);
                        e.printStackTrace(printWriter);
                        governanceAssessDetail.setAssessExceptionMsg(stringWriter.toString().substring(0,Math.min(stringWriter.toString().length(),2000)));
                    }
                    governanceAssessDetail.setCreateTime(new Date());
                    governanceAssessDetails.add(governanceAssessDetail);
                }

                if (governanceMetric.getMetricCode().equals("NO_ACCESS")){
                    GovernanceAssessDetail governanceAssessDetail = new GovernanceAssessDetail();
                    governanceAssessDetail.setAssessDate(assessDate);
                    governanceAssessDetail.setTableName(tableMetaInfo.getTableName());
                    governanceAssessDetail.setSchemaName(tableMetaInfo.getSchemaName());
                    governanceAssessDetail.setMetricId(governanceMetric.getId()+"");
                    governanceAssessDetail.setMetricName(governanceMetric.getMetricName());
                    governanceAssessDetail.setGovernanceType(governanceMetric.getGovernanceType());
                    governanceAssessDetail.setTecOwner(tableMetaInfo.getTableMetaInfoExtra().getTecOwnerUserName());
                    governanceAssessDetail.setAssessScore(BigDecimal.TEN);
                    //判断是否长期无访问
                }
*/

            }
        }

        List<GovernanceAssessDetail> governanceAssessDetailList = completableFutureArrayList.stream().map(result -> result.join()).collect(Collectors.toList());

        //将考评结过写入数据库
//        saveOrUpdateBatch(governanceAssessDetails);
        saveOrUpdateBatch(governanceAssessDetailList);
    }

    @Override
    public void mainAssess(String assessDate) {
        //1.考评
        governanceAssess(assessDate);
        //2.表 人 全局 分数
        governanceAssessTableService.calcGovernanceAssessTable(assessDate);

        governanceAssessTecOwnerService.calcGovernanceAssess(assessDate);

        governanceAssessGlobalService.calcGovernanceAssess(assessDate);
    }
}
